package com.gameloft.futbol;

import javax.microedition.lcdui.Graphics;
import java.util.Vector;
import com.gameloft.futbol.element.screen.*;
import com.gameloft.futbol.element.viewport.*;
import com.gameloft.futbol.element.*;


public abstract class Element
{
	
	protected boolean visible = true;
	protected int x, y, w, h;
	protected int invX, invY, invW, invH;
	protected Vector childs = new Vector();
	protected Element parent = null;
	
	
	public int getX()
	{
		return x;
	}
	
	public int getY()
	{
		return y;
	}
	
	public int getW()
	{
		return w;
	}
	
	public int getH()
	{
		return h;
	}
	
	public void update(long elapsed)
	{
	}
	
	public final void paint(Graphics g)
	{
		if ((invW > 0) && (invH > 0)) paint(g, invX, invY, invW, invH);
		validate();
		paintChilds(g);
	}
	
	public void paint(Graphics g, int x, int y, int w, int h)
	{
	}
	
	public final void setRect(int x, int y, int w, int h)
	{
		boolean rectChanged = (this.x != x) || (this.y != y) || (this.w != w) || (this.h != h);
		
		this.x = x;
		this.y = y;
		this.w = w;
		this.h = h;
		
		if (rectChanged)
		{
			rectChanged();
			invalidate();
			layout();
		}
	}
	
	public void layout() 
	{
	}
	
	public void rectChanged()
	{
	}
	
	public final void validate()
	{
		//Null the cummulative area
		invX = 0;
		invY = 0;
		invW = 0;
		invH = 0;
	}
	
	public final void invalidate()
	{
		//Set the cummulative area as the whole component's area
		invX = x;
		invY = y;
		invW = w;
		invH = h;
	}
	
	public final void invalidateRect(int rectX, int rectY, int rectW, int rectH)
	{
		//If the cummulative area equals the whole component then skip
		if ((invX == x) && (invY == y) && (invW == w) && (invH == h)) return;
		
		//Intersect rect with component's rect. Resulting rectW and/or rectH
		//might be equal or less to 0 when there is no intersection.
		int x1 = (rectX > x) ? rectX : x;
		int y1 = (rectY > y) ? rectY : y;
		int x2 = (rectX+rectW < x+w) ? rectX+rectW : x+w;
		int y2 = (rectY+rectH < y+h) ? rectY+rectH : y+h;
		rectX = x1;
		rectY = y1;
		rectW = x2 - x1;
		rectH = y2 - y1;
		
		//If the rects intersect
		if ((rectW > 0) && (rectH > 0))
		{
			if ((invW <= 0) && (invH <= 0))
			{
				//Set cummulative area as this first invalid rect
				invX = rectX;
				invY = rectY;
				invW = rectW;
				invH = rectH;
			}
			else
			{
				//Otherwise calculate the new cummulative area by Union
				x1 = (rectX < invX) ? rectX : invX;
				y1 = (rectY < invY) ? rectY : invY;
				x2 = (rectX+rectW > invX+invW) ? (rectX+rectW) : (invX+invW);
				y2 = (rectY+rectH > invY+invH) ? (rectY+rectH) : (invY+invH);
				invX = x1;
				invY = y1;
				invW = x2 - x1;
				invH = y2 - y1;
			}
		}
	}
	
	public final void propagateInvalidation()
	{
		for (int i = 0; i < childs.size(); i++)
		{
			Element elem = (Element)(childs.elementAt(i));
			elem.checkInvalidation(invX, invY, invW, invH);
			elem.propagateInvalidation();
		}
	}
	
	public final void checkInvalidation(int rectX, int rectY, int rectW, int rectH)
	{
		//Intersect parent invalidation rectangle with this element's area
		int x1 = (rectX > x) ? rectX : x;
		int y1 = (rectY > y) ? rectY : y;
		int x2 = (rectX+rectW < x+w) ? rectX+rectW : x+w;
		int y2 = (rectY+rectH < y+h) ? rectY+rectH : y+h;
		rectX = x1;
		rectY = y1;
		rectW = x2 - x1;
		rectH = y2 - y1;
		
		//Invalidate area where rects intersect
		if ((rectW > 0) && (rectH > 0)) invalidateRect(rectX, rectY, rectW, rectH);
	}
	
	public final void setParent(Element parent)
	{
		this.parent = parent;
	}
	
	public final Element getParent()
	{
		return this.parent;
	}
	
	public final void setVisible(boolean visible)
	{
		if (!this.visible && visible) invalidate();
		this.visible = visible;
	}
	
	public final boolean isVisible()
	{
		return this.visible;
	}
	
	public final void updateChilds(long elapsed)
	{
		for (int i = 0; i < childs.size(); i++)
		{
			Element elem = (Element)(childs.elementAt(i));
			if (elem.isVisible()) elem.update(elapsed);
		}
	}
	
	public final void paintChilds(Graphics g)
	{
		for (int i = 0; i < childs.size(); i++)
		{
			Element elem = (Element)(childs.elementAt(i));
			if (elem.isVisible()) elem.paint(g);
		}
	}
	
	public final void appendChild(Element child)
	{
		childs.addElement(child);
		child.setParent(this);
	}
	
	public final Element getChild(int index)
	{
		return (Element)(childs.elementAt(index));
	}
	
	public final void removeChild(Element child)
	{
		childs.removeElement(child);
		child.setParent(null);
	}
	
	public final int numChilds()
	{
		return childs.size();
	}
	
}